Module Skins

Tuple Documentation of module_skins.py
Each skin record contains the following fields:
1) Skin id: used for referencing skins.
2) Skin flag: skin will use this morph key/frame of a mesh if multiple are given.
3) Body mesh.
4) Calf mesh (left one).
5) Hand mesh (left one).
6) Head mesh.
7) Face keys (list).
8) List of hair meshes.
9) List of beard meshes.
10) List of hair textures.
11) List of beard textures.
12) List of face textures.
13) List of voices.
14) Skeleton name.
15) Scale (doesn't fully work yet).
16) Blood particles 1 (do not add this if you wish to use the default particles).
17) Blood particles 2 (do not add this if you wish to use the default particles).
18) Face key constraints (do not add this if you do not wish to use it).

module_skins.py is where all the skins for the troops and heroes are defined. They are getting used for genders as well as for different races, so whenever you wish to make a new skin for troops, this is the file you will be modding. You can have a maximum of 16 different skins which is given by header_troops.py and cannot be increased:[1]

								
									troop_type_mask = 0x0000000f
tf_hero = 0x00000010

If each race has a male and female version, then there will be 8 races. Take note that you can have only two races at the multiplayer because the netcode uses only 1 bit for the skin[2] which are usually used for the male and female skin.

Adding a New Skin

Note that you don't need a new race unless you want to change any of the following: body mesh, face shape, war cries, death noises, blood effects. The rest can be done really easily with extra face textures and careful face code usage. If you are adamant about having different face shapes, be aware that you would have to make the meshes and vertex animations yourself, fit the beards to the new mesh, and make a bunch of new textures with different mapping.[3]

In the Native Module System you can either reactivate the skin "undead", by removing the # in front of it, or you add following lines beneath it (but before last ]):[4]

								
									(
  "<race>", 0,
  "<race>_body", "race_calf_l", "race_handL",
  "<race>_head", race_face_keys,
  [],
  [],
  [],
  [],
  [("<RACE>face_a",0xffffffff,[]),("<RACE>face_b",0xffcaffc0,[]),], #face textures
  [], #voice sounds
  "skel_human", 1.0,
),

Change all <race> placeholders to the name of your new race and models. The models which are refered here, are stored in body_meshes.brf. skel_* referes to the skeleton for the race. If you want to add Dwarves, Goblins, Hobbits, Giants or something like this, you will probably want to change this and need a custom skeleton. Afterwards add in header_troops.py the new skin flag. You will see there the following entries:

								
									#Troop flags
tf_male = 0
tf_female = 1
##tf_undead = 2

When adding a new race, you should add them here after the commented-out undeads (or replacing that line). You need to remember that the number which follows the skin must be unique (the undeads are commented out, so you can use 2). So it should look like:

								
									tf_dwarf          = 2
tf_hobbit = 3

Now you can use the new troop flag for all troop entries which should have the new skin. Next, if you want race to be selectable for player, go to module_game_menus.py and search for ("start_male". Under this:

								
									("start_female",[],"Female",
  [
  (troop_set_type, "trp_player", 1),
  (assign, "$character_gender", tf_female),
  (jump_to_menu, "mnu_start_character_1"),
  ]
  ),

but before ("go_back",[],"Go back", you have to add something like this:

								
									("start_<race>",[],"<Race>",
  [
  (troop_set_type, "trp_player", 2),
  (assign, "$character_gender", tf_<race>),
  (jump_to_menu, "mnu_start_character_1"),
  ]
  ),

Note that the 2 after "trp_player" refers to the number which you used in header_troops.py.

Skin Flag and Morph Key

Tuple field 2, Skin Flag, determines which morph key is getting used for that skin. Basically you can use this bit to tell the game if the skin (in most cases a race) requires some body transformation, in the same way as the female armour has narrower shoulders and breasts. If you open up OpenBRF and look at an armour which features a feminised form you will notice that the female form will be in frame number two with time 10. To tell the game to use this vertex animation frame and time for a particular race you use skf_use_morph_key_10 as the time of the frame is 10. Following the same logic you can create your own new frames for particular races and use skf_use_morph_key_20 up to skf_use_morph_key_70.[5] The available flags at header_skins.py determine that you cannot have more than eight morph keys for the frames.

While you should use a different vertex animation frame for each race that use different skeleton (you can use OpenBRF to reskeletonize the armors and add the frames, see the sections Reskeletonize and Vertex Animations),[6] the game engine only makes use of the morph key if such a frame is given. If you assign an armour[7] to a troop of a race with a different skeleton which has not such vertex animation frame given, the game will use the default one.

Face Keys Code

Each face code consists of hexadecimal numbers in a specific order that define all the traits of a person (hair color, age, beard type etc. etc.), with the traits having a range (let's say 00 would be almost closed eyelids, ff widely opened eyelids, and then everything in between).[8]

face codes explained (Yoshiboy, random face code generator)

documentation face key string (Dusk Voyager, Modding Q&A, and k61824, Modding Q&A)

You can get a face that ages by giving the material of your face an old version texture as diffuseB and old version normal map as specular (dunde, Modding Q&A)

You might get an issue where faces are white from a distance but turn normal at closer distance. This is because you need a .LOD material (note the capitals) as well as meshes. Look at how everything else is set up in materials_face_gen (Somebody, Modding Q&A and Modding Q&A)

If you are using a face key on a register note that it doesn't use the 0x (also remember to set both keys or use the default operation) (kalarhan, Modding Q&A)

								
									(str_store_string, s1, "@000000000a00000136db6db6db6db6db00000000001db6db0000000000000000"),
								
							

face key stuff (dstn, Mount & Blade Modding Discord)

Skin Colour

integrate post here (Yoshiboy, Modding Q&A)

Vertex painting (GetAssista, Modding Q&A)

skin colours troops (Somebody, Modding Q&A)

Skin Colour (Somebody, Modding Q&A)

Vertex colour body (Somebody, Modding Q&A)

forearm vertex colour (Somebody, Modding Q&A)

skin coloured meshes (jacobhinds, Mount & Blade Modding Discord)

face colour codes (Leonion (credit), Modding Q&A)

Other materials for hair, (xPearse, Modding Q&A)

some module skins explanations (snouz (credit), Modding Q&A)

face key registers (cmpxchg8b, [WB] Warband Script Enhancer v3.2.0)

Some skin stuff (jcsm130988 (credit), Body-Head Color Tone Mismatch)

Scaling Problems

Tuple field 15, Scale, is an interesting but also sadly not fully functional field. The scale factor multiplies everything, so the skeleton, the hitboxes and all meshes getting used by troops with the respective skin flag. It seems to be thus an easy useable way to create Dwarves or Giants. The walk cycles for shorter races are faster while the ones for bigger races are slowier which is in most cases wanted. Scale comes however with some drawbacks: If the troop gets hit by missiles, the missiles sticking in the troop scale with the same factor.[9] Also it might come to an scale up bug, a ragdoll issue, when the size is set to an factor bigger than 1. That one might however be fixable by delaying the time the death agent turning into a ragdoll on any death animations[10] or fixing the associated hitboxes.[11]

For a more detailed explanation it is recommended to read the report of scale experiments performed by Khamukkamu which contains a variety of tests, explanations and summaries.[12] It is also recommended to look up how the scale factor is getting used in Viking Conquest: the developers used their largest character (Tall) to be of the standard (scale = 1) size. From there, they reduced the scale of each skin (something like normal height=0.9, short=0.85, child=0.75). Beside the faster walk cycles for the shorter/normal characters they found thus a good way around the other above-mentioned issues.

Skins for Horses

You cannot add a new horse skeleton.[13] However, you can vary its scale. Use for this in module_items.py the entry horse_scale(110) for a bigger horse and horse_scale(90) for a smaller horse, you can experiment around with them. horse_scale(30) can for example be used to animate cats with the horse skeleton and animations.[14] Be aware that the set of animations is the same for every mount. It's however possible to find workarounds here as well as some mods removed for example the galloping by mounting the mount on one bone to get a proper futuristic motorbike.[15]

dynamic positioning of horse skeleton (Norwood Reaper, Modding Q&A)

Bones List

There are two lists of bones, one for the human agents and one for the horse agents, which are defined at some Module Systems in header_common.py.[16] That is not always the case though, Native hasn't defined them at all and in Viking Conquest and Napoleonic Wars you will one find bone lists for the human agent. You don't have to add these lists to your Module System although you need to if you want to reference the bones also by names and not only numbers. Between the bone lists you can see a reference picture for all the bone positions:[17]

									
										#Human bones
hb_abdomen = 0
hb_thigh_l = 1
hb_calf_l = 2
hb_foot_l = 3
hb_thigh_r = 4
hb_calf_r = 5
hb_foot_r = 6
hb_spine = 7
hb_thorax = 8
hb_head = 9
hb_shoulder_l = 10
hb_upperarm_l = 11
hb_forearm_l = 12
hb_hand_l = 13
hb_item_l = 14
hb_shoulder_r = 15
hb_upperarm_r = 16
hb_forearm_r = 17
hb_hand_r = 18
hb_item_r = 19
									
										#Horse bones
hrsb_pelvis = 0
hrsb_spine_1 = 1
hrsb_spine_2 = 2
hrsb_spine_3 = 3
hrsb_neck_1 = 4
hrsb_neck_2 = 5
hrsb_neck_3 = 6
hrsb_head = 7
hrsb_l_clavicle = 8
hrsb_l_upper_arm = 9
hrsb_l_forearm = 10
hrsb_l_hand = 11
hrsb_l_front_hoof = 12
hrsb_r_clavicle = 13
hrsb_r_upper_arm = 14
hrsb_r_forearm = 15
hrsb_r_hand = 16
hrsb_r_front_hoof = 17
hrsb_l_thigh = 18
hrsb_l_calf = 19
hrsb_l_foot = 20
hrsb_l_back_hoof = 21
hrsb_r_thigh = 22
hrsb_r_calf = 23
hrsb_r_foot = 24
hrsb_r_back_hoof = 25
hrsb_tail_1 = 26
hrsb_tail_2 = 27

The hit detection has nothing to do with the bones itself but with the spherical hitboxes around them.[18] The game engine checks the collision between one of target's hitboxes with a capsule attached to the right item bone, so bone number 19.[19] At this point it is important to know that the order of the existing bones cannot be changed. The game engine uses hardcoded indices all over the place, at damage calculation, headshots or attaching meshes just to name a few.[20]

Blood Particles

open question about new races blood (Khamukkamu, Modding Q&A)

Blood on agents (Jacobhinds, Putting blood on agents)

blood particle (K700, [WB] Warband Script Enhancer v4.8.0 for 1.174)

Remove blood from armour (GetAssista and Somebody, Modding Q&A) or troop (Specialists, Modding Q&A)

Skin/Gender/Race-based Voice Entries

Tuple field 13, the list of voices, is something which gets often missed when adding new skins.[21] Looking at the Native man skin entry, you can see the following sound entries for different occassions, like when the agent dies, gets hits, yells or makes a victory cheer:

								
									[(voice_die,"snd_man_die"),(voice_hit,"snd_man_hit"),(voice_grunt,"snd_man_grunt"),(voice_grunt_long,"snd_man_grunt_long"),(voice_yell,"snd_man_yell"),(voice_stun,"snd_man_stun"),(voice_victory,"snd_man_victory")], #voice sounds
								
							

Compare it to the Native woman skin entry and you will discover that it has far less entries:[22]

								
									[(voice_die,"snd_woman_die"),(voice_hit,"snd_woman_hit"),(voice_yell,"snd_woman_yell")], #voice sounds
								
							

A look into header_skins.py reveals which voice events can get used by modders:

								
									voice_die        = 0     # Agent dies
voice_hit = 1 # Agent gets hit
voice_grunt = 2 # Unmounted agent attacks with a weapon
voice_grunt_long = 3 # Unmounted agent attacks powerfully with a weapon
voice_yell = 4 # Unmounted AI-agent comes close or readies an attack in a team fight, or player holds attack after sprinting
voice_warcry = 5 # Unused
voice_victory = 6 # Agent makes a victory cheer
voice_stun = 7 # Agent gets stunned